﻿using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;

namespace IOP.Extension.Cache
{
    /// <summary>
    /// 内存缓存
    /// </summary>
    public class MemoryCacheService : ICacheService
    {
        /// <summary>
        /// 内存缓存接口
        /// </summary>
        private readonly IMemoryCache _memoryCache;
        /// <summary>
        /// 日志
        /// </summary>
        private readonly ILogger _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="cache"></param>
        public MemoryCacheService(IMemoryCache cache, ILogger<MemoryCacheService> logger)
        {
            _memoryCache = cache;
            _logger = logger;
        }

        /// <summary>
        /// 判断缓存项是否存在
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <returns></returns>
        public bool Exists(string key)
        {
            try
            {
                if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));
                return _memoryCache.TryGetValue(key, out object value);
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message + e.StackTrace);
                return false;
            }
        }

        /// <summary>
        /// 获取值
        /// </summary>
        /// <param name="key">键</param>
        /// <returns></returns>
        public object Get(string key)
        {
            try
            {
                _memoryCache.TryGetValue(key, out object result);
                return result;
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message + e.StackTrace);
                throw e;
            }
        }
        /// <summary>
        /// 获取值
        /// </summary>
        /// <typeparam name="TItem"></typeparam>
        /// <param name="key">键</param>
        /// <returns></returns>
        public TItem Get<TItem>(string key)
        {
            try
            {
                _memoryCache.TryGetValue(key, out TItem item);
                return item;
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message + e.StackTrace);
                throw e;
            }
        }
        /// <summary>
        /// 尝试获取值
        /// </summary>
        /// <typeparam name="TItem"></typeparam>
        /// <param name="key">键</param>
        /// <param name="item">值</param>
        public void TryGetValue<TItem>(string key, out TItem item)
        {
            item = default(TItem);
            try
            {
                _memoryCache.TryGetValue(key, out item);
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message + e.StackTrace);
            }
        }
        /// <summary>
        /// 通过Key列表获取多个缓存项
        /// </summary>
        /// <param name="keys"></param>
        /// <returns></returns>
        public IDictionary<string, object> GetRange(IEnumerable<string> keys)
        {
            try
            {
                var result = new Dictionary<string, object>();
                foreach (var key in keys)
                {
                    _memoryCache.TryGetValue(key, out object item);
                    result.Add(key, item);
                }
                return result;
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message + e.StackTrace);
                throw e;
            }
        }

        /// <summary>
        /// 移除一项
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Remove(string key)
        {
            try
            {
                _memoryCache.Remove(key);
                return !Exists(key);
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message + e.StackTrace);
                throw;
            }
        }
        /// <summary>
        /// 移除Key存在于参数列表中的项
        /// </summary>
        /// <param name="keys"></param>
        /// <returns></returns>
        public void RemoveRange(IEnumerable<string> keys)
        {
            try
            {
                keys.ToList().ForEach(item => _memoryCache.Remove(item));
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message + e.StackTrace);
                throw e;
            }
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <returns></returns>
        public bool Set(string key, object value)
        {
            try
            {
                return _memoryCache.Set(key, value) != null ? true : false;
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message + e.StackTrace);
                return false;
            }
        }
        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="absoluteExpiration">绝对过期时间</param>
        /// <returns></returns>
        public bool Set(string key, object value, DateTimeOffset absoluteExpiration)
        {
            try
            {
                return _memoryCache.Set(key, value, absoluteExpiration) != null ? true : false;
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message + e.StackTrace);
                throw e;
            }
        }


        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expiresIn"></param>
        /// <returns></returns>
        public bool Set(string key, object value, TimeSpan expiresIn)
        {
            try
            {
                return _memoryCache.Set(key, value, expiresIn) != null ? true : false;
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message + e.StackTrace);
                throw e;
            }
        }

        /// <summary>
        /// 设置缓存(泛型方法)
        /// </summary>
        /// <typeparam name="TItem"></typeparam>
        /// <param name="key"></param>
        /// <param name=""></param>
        /// <returns></returns>
        public bool Set<TItem>(string key, TItem item) where TItem : class
        {
            try
            {
                return _memoryCache.Set(key, item) != null ? true : false;
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message + e.StackTrace);
                throw e;
            }
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <typeparam name="TItem"></typeparam>
        /// <param name="key"></param>
        /// <param name="item"></param>
        /// <param name="absoluteExpiration"></param>
        /// <returns></returns>
        public bool Set<TItem>(string key, TItem item, DateTimeOffset absoluteExpiration) where TItem : class
        {
            try
            {
                return _memoryCache.Set(key, item, absoluteExpiration) != null ? true : false;
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message + e.StackTrace);
                throw e;
            }
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <typeparam name="TItem"></typeparam>
        /// <param name="key"></param>
        /// <param name="item"></param>
        /// <param name="expiresIn"></param>
        /// <returns></returns>
        public bool Set<TItem>(string key, TItem item, TimeSpan expiresIn) where TItem : class
        {
            try
            {
                return _memoryCache.Set(key, item, expiresIn) != null ? true : false;
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message + e.StackTrace);
                throw e;
            }
        }
    }
}
